import { Point2 } from "../point/Point2";
import { Point3 } from "../point/Point3";
import { Vector3 } from "../vector/Vector3";
import { XYZ } from "../coord/XYZ";

/**
* @description 3x3矩阵
* 行主序
*  1, 0, 0
*  0, 1, 0
*  0, 0, 1
* @author xuld
* @date 2024-11-11
* @lastEditTime 2024-11-11 09:46:27
* @lastEditors xuld
*/

export class Matrix3 {
    private _data: number[][];

    public constructor(data?: number[][]) {
        if (data) {
            //验证是否是3x3矩阵
            if (this.checkArray3(data)) {
                data.forEach(item => {
                    this.checkArray3(item);
                })
            }
            this._data = this.rawDeepClone(data);
        }
        else {
            // 默认单位矩阵
            this._data = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
        }
    }

    /**
     * @description 验证是否是3个元素的数组
     * @param item 被验证的数组
     * @returns true 是3个元素的矩阵，抛异常则不是
     */
    private checkArray3(item: any): boolean {
        if (item instanceof Array && item.length == 3) {
            return true
        } else {
            throw new Error("Parameter needs 3 array");
        }
    }

    /**
     * @description 获取数据第i行第j列的值
     * @param i - 行索引
     * @param j - 列索引
     * @returns 矩阵元素值
     */
    public get(i: number, j: number): number {
        if (i < 0 || i >= 3 || j < 0 || j >= 3) {
            throw new Error("Index out of bounds");
        }
        return this._data[i][j];
    }

    /**
     * @description 设置第i行第j列的值
     * @param i - 行索引
     * @param j - 列索引
     * @param value - 要设置的值
     */
    public set(i: number, j: number, value: number) {
        if (i < 0 || i >= 3 || j < 0 || j >= 3) {
            throw new Error("Index out of bounds");
        }
        this._data[i][j] = value;
    }

    /**
     * @description 设置矩阵对角线元素的值
     * @param x - 第一个对角线元素(0,0)
     * @param y - 第二个对角线元素(1,1)
     * @param z - 第三个对角线元素(2,2)
     */
    public setDiagonal(x: number, y: number, z: number): void {
        this._data[0][0] = x;
        this._data[1][1] = y;
        this._data[2][2] = z;
    }

    /**
     * @description 获取原始数据二维数组
     * @returns 矩阵的原始数据数组
     */
    public get raw(): number[][] {
        return this._data;
    }

    /**
     * @description 获取单位矩阵
     * @returns 3x3单位矩阵
     */
    public static Identity(): Matrix3 {
        let mat: Matrix3 = new Matrix3();
        return mat;
    }

    /**
     * @description 获取零矩阵
     * @returns 3x3零矩阵
     */
    public static Zero(): Matrix3 {
        let mat: Matrix3 = new Matrix3();
        for (let i = 0; i < 3; i++) {
            mat._data[i][i] = 0;
        }
        return mat;
    }

    /**
   * @description 矩阵与标量相乘
   * @param scalar - 标量值
   * @returns 返回一个新的矩阵
   */
    public multiply(scalar: number): Matrix3 {
        if (typeof scalar !== 'number' || isNaN(scalar) || !isFinite(scalar)) {
            throw new Error("Invalid scalar value");
        }
        let mat = new Matrix3();
        for (let i = 0; i < 3; i++) {
            for (let j = 0; j < 3; j++) {
                mat._data[i][j] = this._data[i][j] * scalar;
            }
        }
        return mat;
    }

    /**
    * @description 矩阵与标量相乘，改变自身
    * @param scalar - 标量值
    * @returns 返回修改后的矩阵
    */
    public multiplySelf(scalar: number): Matrix3 {
        for (let i = 0; i < 3; i++) {
            for (let j = 0; j < 3; j++) {
                this._data[i][j] = this._data[i][j] * scalar;
            }
        }
        return this;
    }

    /**
    * @description 矩阵相乘 this X mat 不改变自己
    * @param mat - 矩阵
    * @returns 返回一个新的矩阵
    */
    public multiplyMatrix(mat: Matrix3): Matrix3 {
        let newMat = new Matrix3();
        let i: number;
        let j: number;
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++)
                newMat._data[i][j] = this._data[i][0] * mat._data[0][j] +
                    this._data[i][1] * mat._data[1][j] +
                    this._data[i][2] * mat._data[2][j];
        }
        return newMat;
    }

    /**
    * @description 矩阵相乘 this X mat 改变自己
    * @param mat - 矩阵
    * @returns 返回修改后的矩阵
    */
    public multiplyMatrixSelf(mat: Matrix3): Matrix3 {
        let newMat = new Matrix3();
        for (let i = 0; i < 3; i++) {
            for (let j = 0; j < 3; j++)
                newMat._data[i][j] =
                    this._data[i][0] * mat._data[0][j]
                    + this._data[i][1] * mat._data[1][j]
                    + this._data[i][2] * mat._data[2][j]
        }
        this._data = newMat._data
        return this
    }

    /**
    * @description 创建平移矩阵
    * @param pos - 位置
    * @returns 返回一个平移矩阵对象
    */
    public static Translate(pos: Point2): Matrix3 {
        let mat: Matrix3 = new Matrix3();
        mat._data[0][2] = pos.x;
        mat._data[1][2] = pos.y;
        mat._data[2][2] = 1;
        return mat;
    }

    /**
    * @description 旋转矩阵
    * @param rots - 绕各轴的旋转角（弧度），次序z=>y=>x
    * @returns 返回一个旋转矩阵对象
    */
    public static Rotate(rots: XYZ): Matrix3 {
        let mat: Matrix3 = new Matrix3();
        if (rots.x == 0 && rots.y == 0 && rots.z == 0) {
            mat._data[0][0] = 1;
            mat._data[1][1] = 1;
            mat._data[2][2] = 1;
        }
        else {
            let roll = rots.x;
            let pitch = rots.y;
            let yaw = rots.z;

            mat._data[0][0] = Math.cos(yaw) * Math.cos(pitch);
            mat._data[0][1] = Math.cos(yaw) * Math.sin(pitch) * Math.sin(roll) - Math.sin(yaw) * Math.cos(roll);
            mat._data[0][2] = Math.cos(yaw) * Math.sin(pitch) * Math.cos(roll) + Math.sin(yaw) * Math.sin(roll);
            mat._data[1][0] = Math.sin(yaw) * Math.cos(pitch);
            mat._data[1][1] = Math.sin(yaw) * Math.sin(pitch) * Math.sin(roll) + Math.cos(yaw) * Math.cos(roll);
            mat._data[1][2] = Math.sin(yaw) * Math.sin(pitch) * Math.cos(roll) - Math.cos(yaw) * Math.sin(roll);
            mat._data[2][0] = -Math.sin(pitch);
            mat._data[2][1] = Math.cos(pitch) * Math.sin(roll);
            mat._data[2][2] = Math.cos(pitch) * Math.cos(roll);
        }

        return mat;
    }

    /**
    * @description 缩放矩阵
    * @param s - 缩放比例
    * @returns 返回一个缩放矩阵对象
    */
    public static Scale(s: XYZ): Matrix3 {
        if (!s) {
            throw new Error("Scale parameter cannot be null");
        }
        let mat: Matrix3 = new Matrix3();
        mat._data[0][0] = s.x;
        mat._data[1][1] = s.y;
        mat._data[2][2] = s.z;
        return mat;
    }

    /**
    * @description 求逆矩阵，不改变自己
    * @returns 返回一个新的矩阵
    */
    public inverse(): Matrix3 {
        let newMat = new Matrix3();
        const te = this._data,
            m00 = te[0][0], m01 = te[0][1], m02 = te[0][2],
            m10 = te[1][0], m11 = te[1][1], m12 = te[1][2],
            m20 = te[2][0], m21 = te[2][1], m22 = te[2][2],

            n00 = m11 * m22 - m12 * m21,
            n10 = -(m10 * m22 - m20 * m12),
            n20 = m10 * m21 - m20 * m11,
            n01 = - (m01 * m22 - m21 * m02),
            n11 = m00 * m22 - m20 * m02,
            n21 = -(m00 * m21 - m20 * m01),
            n02 = m01 * m12 - m11 * m02,
            n12 = -(m00 * m12 - m10 * m02),
            n22 = m00 * m11 - m01 * m10;

        const det = m00 * n00 + m01 * n10 + m02 * n20;
        if (det === 0) {
            newMat._data = Matrix3.Zero()._data
            return newMat;
        }

        const detInv = 1.0 / det;

        newMat.raw[0][0] = n00;
        newMat.raw[1][0] = n10;
        newMat.raw[2][0] = n20;
        newMat.raw[0][1] = n01;
        newMat.raw[1][1] = n11;
        newMat.raw[2][1] = n21;
        newMat.raw[0][2] = n02;
        newMat.raw[1][2] = n12;
        newMat.raw[2][2] = n22;
        newMat.multiplySelf(detInv);
        return newMat;
    }

    /**
    * @description 求逆矩阵..改变自身
    * @returns 返回修改后的矩阵
    */
    public inverseSelf(): Matrix3 {
        const te = this._data,
            m00 = te[0][0], m01 = te[0][1], m02 = te[0][2],
            m10 = te[1][0], m11 = te[1][1], m12 = te[1][2],
            m20 = te[2][0], m21 = te[2][1], m22 = te[2][2],

            n00 = m11 * m22 - m12 * m21,
            n10 = -(m10 * m22 - m20 * m12),
            n20 = m10 * m21 - m20 * m11,
            n01 = - (m01 * m22 - m21 * m02),
            n11 = m00 * m22 - m20 * m02,
            n21 = -(m00 * m21 - m20 * m01),
            n02 = m01 * m12 - m11 * m02,
            n12 = -(m00 * m12 - m10 * m02),
            n22 = m00 * m11 - m01 * m10;

        const det = m00 * n00 + m01 * n10 + m02 * n20;
        if (det === 0) {
            this._data = Matrix3.Zero()._data
            return this;
        }

        const detInv = 1.0 / det;

        this._data[0][0] = n00;
        this._data[1][0] = n10;
        this._data[2][0] = n20;
        this._data[0][1] = n01;
        this._data[1][1] = n11;
        this._data[2][1] = n21;
        this._data[0][2] = n02;
        this._data[1][2] = n12;
        this._data[2][2] = n22;
        this.multiplySelf(detInv);
        return this;
    }

    /**
    * @description 转置.不改变自身
    * @returns 返回一个新的矩阵
    */
    public transpose(): Matrix3 {
        let mat = new Matrix3();
        let raw = this.rawDeepClone();
        let i: number;
        let j: number;

        for (i = 0; i < 3; i++) {
            for (j = i; j < 3; j++) {
                [raw[i][j], raw[j][i]] = [raw[j][i], raw[i][j]];
            }
        }
        mat._data = raw
        return mat;
    }

    /**
    * @description 转置.改变自身
    * @returns 返回修改后的矩阵
    */
    public transposeSelf(): Matrix3 {
        let raw = this._data;
        let i: number;
        let j: number;

        for (i = 0; i < 3; i++) {
            for (j = i; j < 3; j++) {
                [raw[i][j], raw[j][i]] = [raw[j][i], raw[i][j]];
            }
        }
        return this
    }

    /**
    * @description 矩阵与点相乘, [Mat] X [pt]
    * @param point - 点
    * @returns 返回一个新的点
    */
    public multiplyPoint(point: Point3): Point3 {
        let data = this._data;
        let rlt = new Point3();
        rlt.x = data[0][0] * point.x + data[0][1] * point.y + data[0][2] * point.z;
        rlt.y = data[1][0] * point.x + data[1][1] * point.y + data[1][2] * point.z;
        rlt.z = data[2][0] * point.x + data[2][1] * point.y + data[2][2] * point.z;
        return rlt;
    }

    /**
    * @description 矩阵与向量相乘
    * @param vec - 向量
    * @returns 返回一个新的向量
    */
    public multiplyVector(vec: Vector3): Vector3 {
        let data = this._data;
        let rlt = new Vector3(0, 0, 0);
        rlt.x = data[0][0] * vec.x + data[0][1] * vec.y + data[0][2] * vec.z;
        rlt.y = data[1][0] * vec.x + data[1][1] * vec.y + data[1][2] * vec.z;
        rlt.z = data[2][0] * vec.x + data[2][1] * vec.y + data[2][2] * vec.z;
        return rlt;
    }

    /**
    * @description 获取矩阵列.
    * @param result - 结果
    * @param colIx - 列索引（第一列:0, 第二列1, 第三列2）
    * @returns 返回一个新的向量
    */
    public getColumn(result: Vector3, colIx: number): Vector3 {
        if (colIx < 0 || colIx >= 3) {
            throw new Error("Column index out of bounds");
        }
        let data = this._data;
        result.coord.set(
            data[0][colIx],
            data[1][colIx],
            data[2][colIx]
        );
        return result;
    }

    /**
    * @description 获取矩阵行
    * @param result - 结果
    * @param rowIx - 行索引（第一行:0, 第二行:1, 第三行:2）
    * @returns 行向量
    */
    public getRow(result: Vector3, rowIx: number): Vector3 {
        if (rowIx < 0 || rowIx >= 3) {
            throw new Error("Row index out of bounds");
        }
        let data = this._data;
        result.coord.set(
            data[rowIx][0],
            data[rowIx][1],
            data[rowIx][2]
        );
        return result;
    }

    /**
    * @description 从源复制三阶矩阵
    * @param src - Matrix3
    * @returns 返回一个新的矩阵
    */
    public copyFrom(src: Matrix3): Matrix3 {
        const tRaw = this._data;
        const sRaw = src.raw;
        for (let i = 0; i < 3; i++) {
            for (let j = 0; j < 3; j++) {
                tRaw[i][j] = sRaw[i][j];
            }
        }
        return this;
    }

    /**
    * @description 克隆三阶矩阵
    * @returns 返回一个新的矩阵
    */
    public clone(): Matrix3 {
        return new Matrix3(this.rawDeepClone());
    }

    /**
    * @description 深拷贝矩阵的原始数据
    * @param data - 要拷贝的数据，如果不提供则使用当前矩阵数据
    * @returns 新的二维数组，包含矩阵数据的深拷贝
    * @private
    */
    private rawDeepClone(data?: number[][]): number[][] {
        const source = data || this._data;
        let raw: number[][] = [[], [], []];
        for (let i = 0; i < 3; i++) {
            for (let j = 0; j < 3; j++) {
                raw[i][j] = source[i][j];
            }
        }
        return raw;
    }

    /**
    * @description 获取参数a
    * @returns 获取参数a
    */
    public get a(): number {
        return this._data[0][0];
    }

    /**
    * @description 获取参数b
    * @returns 获取参数b
    */
    public get b(): number {
        return this._data[0][1];
    }

    /**
    * @description 获取参数c
    * @returns 获取参数c
    */
    public get c(): number {
        return this._data[1][0];
    }

    /**
    * @description 获取参数d
    * @returns 获取参数d
    */
    public get d(): number {
        return this._data[1][1];
    }

    /**
    * @description 获取参数tx
    * @returns 获取参数tx
    */
    public get tx(): number {
        return this._data[0][2];
    }

    /**
    * @description 获取参数ty
    * @returns 获取参数ty
    */
    public get ty(): number {
        return this._data[1][2];
    }
}
